#ifndef _SHADER_H_
#define _SHADER_H_

#include <string>

class ShaderSource {

public:

	// Constructs a fragment shader.
	ShaderSource();

	// Constructs a shader of the requested type
	ShaderSource(GLenum type);

	// Deletes the shader using glDeleteShader
	~ShaderSource();

public:		// public methods

	// Load a source file. Throws exception on error
	void load(const char *filename);

	// Compile the current source. Throws exception on error
	void compile();

	// Get the OpenGL name (handle) for this shader
	GLuint getName() const;

	// Get the source 
	const char *getSource() const;

	const char *getInfoLog() const;

private:	// private methods

	void Initialize(GLenum type);

	void updateInfoLog();

	void loadGlExtensions();

private:	// private members

	GLuint mShaderName;
	GLenum mType;
	char *mSource;
	char *mInfoLog;

	//these need to be members, not static members, because getProcAddress could
	//return different pointers for different rendering contexts
	PFNGLCREATESHADERPROC mpglCreateShader;
	PFNGLSHADERSOURCEPROC mpglShaderSource;
	PFNGLCOMPILESHADERPROC mpglCompileShader;
	PFNGLGETSHADERIVPROC mpglGetShaderiv;
	PFNGLDELETESHADERPROC mpglDeleteShader;
	PFNGLGETSHADERINFOLOGPROC mpglGetShaderInfoLog;
};

class ShaderProgram {
public:
	ShaderProgram();

	~ShaderProgram();

public:

	void attach(ShaderSource *source);

	void detach(ShaderSource *source);

	void link();

	void validate();

	void begin();

	void end();

	const char *getInfoLog() const;

	void setUniform(const GLchar *name, GLint value);

	void setUniform(const GLchar *name, GLfloat v0);

	void setUniform(const GLchar *name, GLfloat v0, GLfloat v1);

	void setUniform(const GLchar *name, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);

private:
	GLuint mProgramName;
	char *mInfoLog;

	PFNGLCREATEPROGRAMPROC mpglCreateProgram;
	PFNGLDELETEPROGRAMPROC mpglDeleteProgram;
	PFNGLATTACHSHADERPROC mpglAttachShader;
	PFNGLDETACHSHADERPROC mpglDetachShader;
	PFNGLLINKPROGRAMPROC mpglLinkProgram;
	PFNGLGETPROGRAMIVPROC mpglGetProgramiv;
	PFNGLVALIDATEPROGRAMPROC mpglValidateProgram;
	PFNGLUSEPROGRAMPROC mpglUseProgram;
	PFNGLGETUNIFORMLOCATIONPROC mpglGetUniformLocation;
	PFNGLUNIFORM1IPROC mpglUniform1i;
	PFNGLUNIFORM1FPROC mpglUniform1f;
	PFNGLUNIFORM2FPROC mpglUniform2f;
	PFNGLUNIFORM4FPROC mpglUniform4f;
	PFNGLGETPROGRAMINFOLOGPROC mpglGetProgramInfoLog;

	void updateInfoLog();

	void loadGlExtensions();
};

#endif // _SHADER_H_
